package com.htudata.websocket.endpoint ;

import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import com.htudata.a2service.A2Service;
import com.htudata.common.enums.A2CodeEnum;
import com.htudata.common.enums.PageSeqEnum;
import com.htudata.common.enums.RequestSeqEnum;
import com.htudata.common.enums.WSMsgEnum;
import com.htudata.common.service.TokenService;
import com.htudata.core.util.ResultGenerator;
import com.htudata.core.util.operation.CollectionsOperationUtils;
import com.htudata.core.util.operation.MapOperationUtils;
import com.htudata.core.util.operation.StringOperationUtils;
import com.htudata.equipment.service.EquipmentService;
import com.htudata.grid.service.GridDateService;
import com.htudata.hieyes.flow.service.FlowService;
import com.htudata.hieyes.transctflow.service.TransctFlowService;
import com.htudata.home.service.IFctService;
import com.htudata.home.service.IMntEqpService;
import com.htudata.messager.service.IMessagerService;
import com.htudata.other.service.OtherShowService;
import com.htudata.specialLink.service.SpecialLinkService;
import com.htudata.station.service.StationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@ServerEndpoint("/v1/websocket/{token}/{appCode}")
@Component
public class AgentServerEndpoint {

  private static final Map<String, AgentServerEndpoint> agentServerEndpoints = new ConcurrentHashMap<>();
  
  private static final AtomicInteger onlineCount = new AtomicInteger();
  
  private Session session;
  
  private String token;
  
  private String appCode;
  
  private String a2Info;
  
  private Map<String, JSONObject> interfaceInfos = new ConcurrentHashMap<>();
  
  private static OtherShowService otherShowService;
  
  private static IMntEqpService eqpService;

  private static A2Service a2Service;
  
  private static GridDateService gridDateService;
  
  private static EquipmentService equipmentService;
  
  private static IFctService fctService;
  
  private static StationService stationService;
  
  private static IMessagerService messagerService;
  
  private static SpecialLinkService specialLinkService;
  
  private static FlowService flowService;
  
  private static TransctFlowService transctFlowService;
  
  @OnOpen
  public void onOpen(Session session, @PathParam("token") String token, @PathParam("appCode") String appCode) {
    this.session = session;
    this.token = token;
    this.appCode = appCode;
    Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
    String a2 = null;
    if (CollectionsOperationUtils.isValidCollection(requestParameterMap.get("a2")))
      a2 = ((List<String>)requestParameterMap.get("a2")).get(0);
      String a2Info = null;
      try {
          a2Info = a2Service.validateToken(null, null, a2);
      } catch (Exception e) {
          log.error("validateToken",e);
      }
      if (a2Info == null) {
      try {
        JSONObject resultWithA2Status = ResultGenerator.genResultWithA2Status(ResultGenerator.genResult("0", null), A2CodeEnum.code_0.getCode());
        sendMessage(resultWithA2Status.toJSONString());
        session.close(new CloseReason((CloseReason.CloseCode)CloseReason.CloseCodes.CANNOT_ACCEPT, "Illegal token"));
      } catch (IOException e) {
        log.error("close session ocurre error: {} .", e.getMessage());
      } 
      return;
    } 
    this.a2Info = a2Info;
    agentServerEndpoints.put(this.session.getId(), this);
    addOnlineCount();
    log.info("有新窗口开始监听:" + session.getId() + ", appCode:" + this.appCode + ", 当前在线会话数为:" + getOnlineCount());
    try{
      if (PageSeqEnum.SEQ_003.getCode().equals(appCode)) {
        sendMessage(otherShowService.getBssInfoList(false));
        sendMessage(eqpService.selectMntEqpDataJSON());
        sendMessage(eqpService.selectHisExtreJSON());
        sendMessage(fctService.selectFctDataJSON(null));
        sendMessage(fctService.selectMeteoPublicSatisfctJSON());
      } else if (PageSeqEnum.SEQ_004.getCode().equals(appCode)) {
        sendMessage(eqpService.selectMntEqpDataJSON());
        sendMessage(eqpService.selectHisExtreJSON());
        sendMessage(equipmentService.getAllEquipmentReachJSON());
        sendMessage(equipmentService.getEachEquipmentProportionJSON());
        sendMessage(equipmentService.getEachEquipmentReachJSON());
        sendMessage(stationService.getStationInfoByTypeJSON(null, TokenService.getUserId(a2Info)));
        sendMessage(specialLinkService.geNetworkStatusDataJSON());
      } else if (PageSeqEnum.SEQ_005.getCode().equals(appCode)) {
        sendMessage(specialLinkService.geNetworkStatusDataJSON());
        sendMessage(flowService.getMonitorNodeDataJSON("all", RequestSeqEnum.SEQ_026.getCode()));
        sendMessage(transctFlowService.getMonitorNodeDataJSON("all", RequestSeqEnum.SEQ_027.getCode()));
      } else if (PageSeqEnum.SEQ_006.getCode().equals(appCode)) {
        sendMessage(gridDateService.getEachProportionJSON());
        sendMessage(gridDateService.getAllReachJSON());
        sendMessage(gridDateService.getEachReachJSON());
        sendMessage(gridDateService.getRainFctImgByFctJSON("wcmwf"));
        sendMessage(fctService.selectFctDataJSON("week"));
      } else if (PageSeqEnum.SEQ_007.getCode().equals(appCode)) {
        sendMessage(messagerService.selectMeteoPublicUserCommentJSON());
        sendMessage(fctService.selectMeteoPublicSatisfctJSON());
        sendMessage(messagerService.selectServChannelDataJSON("weibo"));
      }
    }
    catch (Exception e){
      log.error("sendMessage",e);
    }
  }
  
  @OnClose
  public void onClose() {
    agentServerEndpoints.remove(this.session.getId());
    subOnlineCount();
    log.info("有一连接关闭！当前在线会话数为:" + getOnlineCount());
  }
  
  @OnError
  public void onError(Session session, Throwable error) {
    log.error("发生错误", error);
  }
  
  @OnMessage
  public void onMessage(String message, Session session) {
    log.info("收到来自窗口" + session.getId() + "的信息:" + message);
    if (isHeartMessage(message))
      return; 
    try {
      JSONObject json = JSONObject.parseObject(message);
      if (WSMsgEnum.SEQ_000.getCode().equals(json.getString("msgId"))) {
        JSONObject body = json.getJSONObject("body");
        this.interfaceInfos.put(body.getString("seq"), body);
        if (RequestSeqEnum.SEQ_006.getCode().equals(body.getString("seq")))
          try {
            sendMessage(gridDateService.getAllReachJSON());
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_007.getCode().equals(body.getString("seq")))
          try {
            sendMessage(gridDateService.getEachProportionJSON());
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_008.getCode().equals(body.getString("seq")))
          try {
            sendMessage(gridDateService.getEachReachJSON());
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_013.getCode().equals(body.getString("seq")))
          try {
            sendMessage(equipmentService.getAllEquipmentReachJSON());
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_014.getCode().equals(body.getString("seq")))
          try {
            sendMessage(equipmentService.getEachEquipmentProportionJSON());
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_015.getCode().equals(body.getString("seq")))
          try {
            sendMessage(equipmentService.getEachEquipmentReachJSON());
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_016.getCode().equals(body.getString("seq")))
          try {
            sendMessage(equipmentService.getEquipmentDetailsJSON());
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_017.getCode().equals(body.getString("seq")))
          try {
            String data = messagerService.selectServChannelDataJSON(body.getString("servChannel"));
            if (StringOperationUtils.isValidStr2(data))
              sendMessage(data); 
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_019.getCode().equals(body.getString("seq")))
          try {
            int status = (body.getInteger("status") == null) ? -1 : body.getInteger("status").intValue();
            String data = eqpService.selectStationStatusJSON(body.getString("type"), body.getString("areaCode"), status, TokenService.getUserId(this.a2Info));
            if (StringOperationUtils.isValidStr2(data))
              sendMessage(data); 
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_020.getCode().equals(body.getString("seq")))
          try {
            String data = gridDateService.getTimeFileListJSON(body.getString("future"), body
                .getString("fct"), body.getInteger("start").intValue(), body.getInteger("size").intValue());
            sendMessage(data);
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_021.getCode().equals(body.getString("seq")))
          try {
            sendMessage(stationService.getStationInfoByTypeJSON(body.getString("stationType"), TokenService.getUserId(this.a2Info)));
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_022.getCode().equals(body.getString("seq")))
          try {
            sendMessage(gridDateService.getRainFctImgByFctJSON(body.getString("fct")));
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_023.getCode().equals(body.getString("seq")))
          try {
            sendMessage(gridDateService.getGridDetailsJSON(body.getLongValue("dataTime")));
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_030.getCode().equals(body.getString("seq")))
          try {
            sendMessage(flowService.getMonitorNodeDataJSON(body.getString("flowId"), RequestSeqEnum.SEQ_030.getCode()));
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
        if (RequestSeqEnum.SEQ_031.getCode().equals(body.getString("seq")))
          try {
            sendMessage(transctFlowService.getMonitorNodeDataJSON(body.getString("flowId"), RequestSeqEnum.SEQ_031.getCode()));
          } catch (Exception e) {
            log.error("gridDateService",e);
          }  
      } 
    } catch (Exception e) {
      log.error("Parse response error occurred -> {}", e.getMessage());
    } 
  }
  
  private void sendMessage(String message) {
    try {
      if (StringOperationUtils.isValidStr2(message)) {
        this.session.getAsyncRemote().sendText(message);
        Thread.sleep(15L);
      } 
    } catch (Exception e) {
      log.error("send to application: {}.", message);
    } 
  }
  
  public static void sendAll(String json, Map<String, String> tgtAppCodeMap, JSONObject tgtInterfaceInfo) {
    AgentServerEndpoint agentServerEndpoint = null;
    for (Map.Entry<String, AgentServerEndpoint> entry : agentServerEndpoints.entrySet()) {
      agentServerEndpoint = entry.getValue();
      if (MapOperationUtils.isValidMap(tgtAppCodeMap) &&
        !tgtAppCodeMap.containsKey(agentServerEndpoint.appCode))
        continue; 
      if (!MapOperationUtils.isValidMap((Map)tgtInterfaceInfo))
        agentServerEndpoint.sendMessage(json); 
    } 
  }
  
  public boolean isHeartMessage(String message) {
    try {
      JSONObject json = JSONObject.parseObject(message);
      String msgId = json.getString("msgId");
      if (msgId != null && msgId.equals(WSMsgEnum.SEQ_003.getCode()))
        return true; 
    } catch (Exception e) {
      log.error("Parse response error occurred -> {}", e.getMessage());
    } 
    return false;
  }
  
  public Map<String, List<Long>> getCurrentUserIds() {
    Map<String, List<Long>> result = new HashMap<>();
    AgentServerEndpoint agentServerEndpoint = null;
    String key = "userIds";
    long userId = -1L;
    List<Long> userIds = null;
    for (Map.Entry<String, AgentServerEndpoint> entry : agentServerEndpoints.entrySet()) {
      agentServerEndpoint = entry.getValue();
      if (!agentServerEndpoint.appCode.equals(PageSeqEnum.SEQ_003.getCode()))
        continue;
        try {
            userId = TokenService.getUserId(agentServerEndpoint.a2Info);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (result.containsKey(key)) {
        ((List<Long>)result.get(key)).add(Long.valueOf(userId));
        continue;
      } 
      userIds = new ArrayList<>();
      userIds.add(Long.valueOf(userId));
      result.put(key, userIds);
    } 
    return result;
  }
  
  public void sendToALLUser(Map<String, String> map) {
    if (!MapOperationUtils.isValidMap(map))
      return; 
    AgentServerEndpoint agentServerEndpoint = null;
    long userId = -1L;
    for (Map.Entry<String,AgentServerEndpoint> entry : agentServerEndpoints.entrySet()) {
      agentServerEndpoint = entry.getValue();
      if (!agentServerEndpoint.appCode.equals(PageSeqEnum.SEQ_003.getCode()))
        continue;
        try {
            userId = TokenService.getUserId(agentServerEndpoint.a2Info);
        } catch (Exception e) {

        }
        if (!map.containsKey(userId + ""))
        continue; 
      if (StringOperationUtils.isValidStr2(map.get(userId + "")))
        agentServerEndpoint.sendMessage(map.get(userId + "")); 
    } 
  }
  
  public static void sendUserOwnMessage() {
    AgentServerEndpoint agentServerEndpoint = null;
    for (Map.Entry<String, AgentServerEndpoint> entry : agentServerEndpoints.entrySet()) {
      agentServerEndpoint = entry.getValue();
      try{
        if (PageSeqEnum.SEQ_003.getCode().equals(agentServerEndpoint.appCode)) {
          agentServerEndpoint.sendMessage(otherShowService.getBssInfoList(false));
          agentServerEndpoint.sendMessage(eqpService.selectMntEqpDataJSON());
          agentServerEndpoint.sendMessage(eqpService.selectHisExtreJSON());
          agentServerEndpoint.sendMessage(fctService.selectFctDataJSON(null));
          agentServerEndpoint.sendMessage(fctService.selectMeteoPublicSatisfctJSON());
        }
        if (PageSeqEnum.SEQ_004.getCode().equals(agentServerEndpoint.appCode)) {
          agentServerEndpoint.sendMessage(eqpService.selectMntEqpDataJSON());
          agentServerEndpoint.sendMessage(eqpService.selectHisExtreJSON());
          agentServerEndpoint.sendMessage(equipmentService.getAllEquipmentReachJSON());
          agentServerEndpoint.sendMessage(equipmentService.getEachEquipmentProportionJSON());
          agentServerEndpoint.sendMessage(equipmentService.getEachEquipmentReachJSON());
          agentServerEndpoint.sendMessage(stationService.getStationInfoByTypeJSON(null, TokenService.getUserId(agentServerEndpoint.a2Info)));
          agentServerEndpoint.sendMessage(specialLinkService.geNetworkStatusDataJSON());
        }
        if (PageSeqEnum.SEQ_005.getCode().equals(agentServerEndpoint.appCode)) {
          agentServerEndpoint.sendMessage(specialLinkService.geNetworkStatusDataJSON());
          if (agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_026.getCode()) != null)
            agentServerEndpoint.sendMessage(flowService.getMonitorNodeDataJSON("all", RequestSeqEnum.SEQ_026.getCode()));
          if (agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_027.getCode()) != null)
            agentServerEndpoint.sendMessage(transctFlowService.getMonitorNodeDataJSON("all", RequestSeqEnum.SEQ_027.getCode()));
          if (agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_030.getCode()) != null) {
            JSONObject body = agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_030.getCode());
            agentServerEndpoint.sendMessage(flowService.getMonitorNodeDataJSON(body.getString("flowId"), RequestSeqEnum.SEQ_030.getCode()));
          }
          if (agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_031.getCode()) != null) {
            JSONObject body = agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_031.getCode());
            agentServerEndpoint.sendMessage(transctFlowService.getMonitorNodeDataJSON(body.getString("flowId"), RequestSeqEnum.SEQ_031.getCode()));
          }
        }
        if (PageSeqEnum.SEQ_006.getCode().equals(agentServerEndpoint.appCode)) {
          agentServerEndpoint.sendMessage(gridDateService.getEachProportionJSON());
          agentServerEndpoint.sendMessage(gridDateService.getAllReachJSON());
          agentServerEndpoint.sendMessage(gridDateService.getEachReachJSON());
          JSONObject fctDataJSON = agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_011.getCode());
          if (fctDataJSON != null) {
            String time = fctDataJSON.getString("time");
            agentServerEndpoint.sendMessage(fctService.selectFctDataJSON((time == null) ? "week" : time));
          } else {
            agentServerEndpoint.sendMessage(fctService.selectFctDataJSON("week"));
          }
        }
        if (PageSeqEnum.SEQ_007.getCode().equals(agentServerEndpoint.appCode)) {
          agentServerEndpoint.sendMessage(messagerService.selectMeteoPublicUserCommentJSON());
          agentServerEndpoint.sendMessage(fctService.selectMeteoPublicSatisfctJSON());
          if (agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_017.getCode()) != null) {
            JSONObject body = agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_017.getCode());
            agentServerEndpoint.sendMessage(messagerService.selectServChannelDataJSON(body.getString("servChannel")));
          } else {
            agentServerEndpoint.sendMessage(messagerService.selectServChannelDataJSON("weibo"));
          }
        }
        if (agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_022.getCode()) != null) {
          JSONObject body = agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_012.getCode());
          agentServerEndpoint.sendMessage(gridDateService.getGridDetailsJSON(body.getLongValue("dataTime")));
        }
        if (agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_019.getCode()) != null) {
          JSONObject body = agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_019.getCode());
          int status = (body.getInteger("status") == null) ? -1 : body.getInteger("status").intValue();
          agentServerEndpoint.sendMessage(eqpService.selectStationStatusJSON(body.getString("type"), body.getString("areaCode"), status, TokenService.getUserId(agentServerEndpoint.a2Info)));
        }
        if (agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_020.getCode()) != null) {
          JSONObject body = agentServerEndpoint.interfaceInfos.get(RequestSeqEnum.SEQ_020.getCode());
          agentServerEndpoint.sendMessage(gridDateService.getTimeFileListJSON(body.getString("future"), body.getString("fct"), 0, 11));
        }
      }
      catch (Exception e) {
        log.error("sendMessage", e);
      }

    } 
  }
  
  public int getOnlineCount() {
    return onlineCount.get();
  }
  
  private void addOnlineCount() {
    onlineCount.incrementAndGet();
  }
  
  private void subOnlineCount() {
    onlineCount.decrementAndGet();
  }
  
  @Autowired
  public void setA2Service(A2Service a2Service) {
    this .a2Service = a2Service;
  }
  
  @Autowired
  public void setotherShowService(OtherShowService otherShowService) {
    this.otherShowService = otherShowService;
  }
  
  @Autowired
  public void setGridDateService(GridDateService gridDateService) {
    this.gridDateService = gridDateService;
  }
  
  @Autowired
  public void setEquipmentService(EquipmentService equipmentService) {
    this.equipmentService = equipmentService;
  }
  
  @Autowired
  public void setEqpService(IMntEqpService eqpService) {
    this.eqpService = eqpService;
  }
  
  @Autowired
  public void setFctService(IFctService fctService) {
    this.fctService = fctService;
  }
  
  @Autowired
  public void setStationService(StationService stationService) {
    this.stationService = stationService;
  }
  
  @Autowired
  public void setMessagerService(IMessagerService messagerService) {
    this.messagerService = messagerService;
  }
  
  @Autowired
  public void setSpecialLinkService(SpecialLinkService specialLinkService) {
    this.specialLinkService = specialLinkService;
  }
  
  @Autowired
  public void setFlowService(FlowService flowService) {
    this.flowService = flowService;
  }
  
  @Autowired
  public void setTransctFlowService(TransctFlowService transctFlowService) {
    this.transctFlowService = transctFlowService;
  }
}
